﻿// ———————————————————————–
// <copyright file="KMLStyleEngine.cs" company="The MITRE Corporation">
//    Copyright (c) 2010 The MITRE Corporation. All rights reserved.
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
// </copyright>
// ———————————————————————–
/////////////////////////////////////////////////////////////////////////////////////////////////
// KMLStyleEngine.cs - Engine for loading available KML styles from a configuration file.
// Project: IC.NETSOA- KMLStyleEngine
//
// Language:    C#, .NET 4.0
// Platform:    Dell XPS m1530 Windows 7, VS 2010
// Author:      Brian Wilkins - Bedford
//              bwilkins@mitre.org, (781) 271-2332
/////////////////////////////////////////////////////////////////////////////////////////////////

// Copyright (c) 2010 The MITRE Corporation. All rights reserved.
//
// NOTICE
// This software was produced for the U. S. Government
// under Contract No. FA8721-09-C-0001, and is
// subject to the Rights in Noncommercial Computer Software
// and Noncommercial Computer Software Documentation Clause
// (DFARS) 252.227-7014 (JUN 1995)

using System;
using System.IO;
using System.Text;
using System.Web;
using System.Xml;
using System.Xml.Serialization;
using ICNETDAL;

namespace ICNET_KMLStyleEngine
{
  /// <summary>
  /// This class contains the methods used in loading the KML formatting styles from a configuration file. 
  /// </summary>
  public static class KMLStyleEngine
  {
    /// <summary>
    /// The default style.
    /// </summary>
    private const string DEFAULTSTYLE = @"msn caution";
 
    #region Public Delegates/Events

    #endregion

    #region Private Member Variables

    /// <summary>
    /// The non Cursor on Target styles .
    /// </summary>
    private static ICNETSortedStyles nonCoTStyles;

    /// <summary>
    /// The Cursor on Target styles.
    /// </summary>
    private static ICNETSortedStyles cotStyles;

    /// <summary>
    /// The default sytle name.
    /// </summary>
    private static string defaultStyleName;

    #endregion

    #region Constructors

    /// <summary>
    /// Initializes static members of the KMLStyleEngine class.
    /// </summary>
    static KMLStyleEngine()
    {
      nonCoTStyles = new ICNETSortedStyles();
      cotStyles = new ICNETSortedStyles();
      defaultStyleName = DEFAULTSTYLE;

      LoadStyles();
    }

    #endregion

    #region Public Accessors

    #endregion

    #region Public Member Functions

    /// <summary>
    /// Gets the default style ID used in KML formatting.
    /// </summary>
    /// <returns>the default style ID in the form of a string.</returns>
    public static string DefaultStyleId
    {
        get { return @"#" + defaultStyleName; }
    }

    /// <summary>
    /// Gets the appropriate style ID for an item from the exposure cache
    /// </summary>
    /// <param name="type">The type style </param>
    /// <remarks> It only matters whether it is a CoT style or not. </remarks>
    /// <param name="databaseItem">the exposure cache item to try to match a style with </param>
    /// <returns>a string that corresponds to the style</returns>
    public static string GetStyleIdFromMatch(MatchTypeEnum type, ExposureCache databaseItem)
    {
      string val = null;

      if (type == MatchTypeEnum.CoT)
      {
        val = cotStyles.GetStyleIdFromMatch(databaseItem); 
      }
      else
      {
        val = nonCoTStyles.GetStyleIdFromMatch(databaseItem);
      }

      if (String.IsNullOrEmpty(val))
      {
        val = defaultStyleName;
      }

      return @"#" + val;
    }

    /// <summary>
    /// Gets the appropriate style ID for an item from the exposure cache
    /// </summary>
    /// <param name="type">The type style </param>
    /// <remarks> It only matters whether it is a CoT style or not. </remarks>
    /// <param name="databaseItem">the exposure cache item to try to match a style with </param>
    /// <returns>The mtaching style </returns>
    public static ICNETStyle GetStyleFromMatch(MatchTypeEnum type, ExposureCache databaseItem)
    {
      ICNETStyle style = null;

      if (type == MatchTypeEnum.CoT)
      {
        style = cotStyles.GetStyleFromMatch(databaseItem);
      }
      else
      {
        style = nonCoTStyles.GetStyleFromMatch(databaseItem);
      }

      return style;
    }

    public static ICNETStyle GetStyleFromCoTType(string cotType)
    {
      ICNETStyle style = null;

      style = cotStyles.GetStyleFromCoTType(cotType);
      
      return style;
    }

    public static ICNETStyle GetStyleFromContentOrTitle(string content, string title)
    {
      ICNETStyle style = null;

      style = nonCoTStyles.GetStyleFromContentOrTitle(content, title);

      return style;
    }

    /// <summary>
    /// Retrieves the style that matches the given ID
    /// </summary>
    /// <param name="id">The KML name of the style</param>
    /// <returns>Returns the ICNETStyle or null if it cannot be found</returns>
    public static ICNETStyle GetStyleFromId(string id)
    {
        ICNETStyle result = null;

        if (cotStyles != null)
        {
            result = cotStyles.GetStyleFromId(id);
        }

        if (result == null && nonCoTStyles != null)
        {
            result = nonCoTStyles.GetStyleFromId(id);
        }

        return result;
    }

    #endregion

    #region Protected Member Functions

    #endregion

    #region Private Member Functions

    /// <summary>
    /// Loads all of the styles from the KMLStyle.xml file. 
    /// </summary>
    private static void LoadStyles()
    {
      ICNETStyles allStyles;

      XmlSerializer s = new XmlSerializer(typeof(ICNETStyles));
      TextReader r = null;

      string fileName = HttpRuntime.AppDomainAppPath + @"/Resources/ICNET_KMLStyles.xml";

      if (File.Exists(fileName))
      {
        r = new StreamReader(fileName);
      }
      else
      {
        return;
      }

      try
      {
        allStyles = (ICNETStyles)s.Deserialize(r);

        foreach (ICNETStyle style in allStyles.Styles)
        {
          if (style.MatchType == MatchTypeEnum.CoT)
          {
            double key = GetMatchSequenceKey(cotStyles, style);
            cotStyles.Styles.Add(key, style);
          }
          else
          {
            if (style.MatchType == MatchTypeEnum.Default)
            {
              defaultStyleName = style.KMLStyleName;
            }

            double key = GetMatchSequenceKey(nonCoTStyles, style);
            nonCoTStyles.Styles.Add(key, style);
          }
        }

        if (cotStyles.Styles.Count < 1)
        {
          cotStyles = null;
        }

        if (nonCoTStyles.Styles.Count < 1)
        {
          nonCoTStyles = null;
        }
      }
      catch (Exception)
      {
        allStyles = null;
      }
      finally
      {
        r.Close();
        allStyles = null;
      }
    }

    /// <summary>
    /// Gives the key associated with a certain style .
    /// </summary>
    /// <param name="theList">A list that contains all of the styles </param>
    /// <param name="theStyle">The style which the key should be matched to </param>
    /// <returns>The key, as a double.</returns>
    private static double GetMatchSequenceKey(ICNETSortedStyles theList, ICNETStyle theStyle)
    {
      double doubleMatchSequence = 999999;
      int intMatchSequence = 999999;

      if (theStyle.Match != null)
      {
        intMatchSequence = theStyle.Match.MatchSequenceNumber;
        doubleMatchSequence = (float)intMatchSequence;
      }

      double suffix = 0;
      int i = 1;
      while (theList.Styles.ContainsKey(doubleMatchSequence))
      {
        suffix = suffix + (1 / Math.Pow(10, i));
        doubleMatchSequence = (double)intMatchSequence + suffix;
        i++;
      }

      return doubleMatchSequence;
    }
    #endregion
  }
}
